package main

import (
	"Ljohn/reflectTest/baseTypeTest"
	"fmt"
	"reflect"
	"time"
	"unsafe"
)

func main() {
	baseValueOf()
	//typeOfTest()

	//undoneValueOf()

	/*	a := &[3]tttt1{}
		getArrayArgProperty(a)*/

	//makeTest.ReflectTest()

	baseTypeTest.Open()
}

var mapper = make(map[interface{}]map[interface{}]interface{})

type t2 struct {
	q string
}

type tttt1 struct {
	Name  string
	Age   int
	test2 string
	hi    *string
	u1    *User
}
type User struct {
	hi    *string
	word  int
	date1 time.Time
	str2  []string
}

func (s *tttt1) Func1() {
	fmt.Println(s.Age)
}

type myType int

func (my *myType) Hi() {
	fmt.Println("my value ", *my)
}
func (my myType) Get() int {
	fmt.Println("my values ", my)
	return int(my)
}
func (my *myType) Set(x int) {
	*my = myType(x)
}

func undoneValueOf() {

	var s myType = 1
	v := reflect.ValueOf(&s)
	v1 := reflect.TypeOf(&s)

	fmt.Println(" v  ", v.NumMethod())
	fmt.Println(" v1  ", v1.NumMethod())

	var para []reflect.Value
	para = append(para, reflect.ValueOf(11))
	fmt.Println(v.Method(2).Call(para))

	para = append(para, reflect.ValueOf(&s))
	fmt.Println(v1.Method(0).Func.Call(para[1:]))
}

func structValueOfProperty(v reflect.Value) {
	for i := 0; i < v.NumField(); i++ {
		argType := reflect.Indirect(v.Field(i))
		if argType.Kind() == reflect.Struct {
			structValueOfProperty(argType)
		} else {
			if argType.CanSet() == true && argType.Kind() == reflect.Int {
				argType.SetInt(10)
			}
			fmt.Println(argType.Kind(), "     : ", argType, "   ", argType.CanSet())
		}
	}
}

func baseValueOf() {

	a1 := [...]int{1, 2, 3, 4}
	v1 := reflect.ValueOf(&a1)
	v2 := reflect.ValueOf(a1)

	fmt.Println(v1.Kind()) //PTR v1.Elem -> 1,2,3,4

	fmt.Println(v2.Kind()) //Array
	//fmt.Println(v1.Len()) 指针类型不能遍历长度
	fmt.Println(v2.Len()) // 4

	v1.Elem().Index(0).SetInt(10)
	//v2.Elem().Index(1).SetInt(20) 只能是只能类型才能修改源目标的值
	fmt.Println(a1)

	// Elem只能作用于PTR,Array,Slice都会报错
	//fmt.Println(v2.Elem())
	a2 := []int{1, 2, 3, 4}
	/*vv1 := reflect.ValueOf(a2)
	fmt.Println(vv1.Elem())*/
	fmt.Println("---------")
	vv1 := reflect.ValueOf(a2)
	fmt.Println(vv1.Type().Elem())
	fmt.Println("---------")
}

func typeOfTest() {
	ss := "ws"
	s1 := "sssss"
	t := &tttt1{"1", 1, "sss", &ss, &User{&s1, 1, time.Now(), []string{"12", "23"}}}
	//t1 :="sss"
	//t2 := time.Now()

	//v :=reflect.TypeOf(t).Elem()
	//v1 :=reflect.TypeOf(t1)
	//v2 :=reflect.TypeOf(t2)

	//fmt.Println(v.Kind())
	//fmt.Println(v.Field(1))
	//fmt.Println(v1.Kind())
	//fmt.Println(v2.Kind())
	//fmt.Println(v1.Field(0))
	getStructArgProperty(t)
	getArrayArgProperty(t)
}

func getArrayArgProperty(t interface{}) {
	var v reflect.Type
	if reflect.TypeOf(t).Kind() == reflect.Ptr {
		if reflect.TypeOf(t).Elem().Kind() == reflect.Array {
			fmt.Println("我是属猪1")
		} else if reflect.TypeOf(t).Elem().Kind() == reflect.Slice {
			fmt.Println("我是切片1")
		} else {
			fmt.Println("不是要的1")
			return
		}
		fmt.Println(reflect.TypeOf(t), reflect.TypeOf(t).Elem(), reflect.TypeOf(t).Elem().Elem())
		v = reflect.TypeOf(t).Elem().Elem()
	} else {
		if reflect.TypeOf(t).Kind() == reflect.Array {
			fmt.Println("我是属猪2")
		} else if reflect.TypeOf(t).Kind() == reflect.Slice {
			fmt.Println("我是切片2")
		} else {
			fmt.Println("不是要的2")
			return
		}
		v = reflect.TypeOf(t).Elem()
	}
	fmt.Println(v.Kind())
	run(v)
}

func getStructArgProperty(t interface{}) {
	var v reflect.Type
	if reflect.TypeOf(t).Kind() == reflect.Ptr {
		if reflect.TypeOf(t).Elem().Kind() != reflect.Struct {
			fmt.Println("不是结构体")
			return
		}
		v = reflect.TypeOf(t).Elem()
	} else {
		if reflect.TypeOf(t).Kind() != reflect.Struct {
			fmt.Println("不是结构体")
			return
		}
		v = reflect.TypeOf(t)
	}
	run(v)
}
func run(v reflect.Type) {
	for i := 0; i < v.NumField(); i++ {
		argType := v.Field(i)
		if argType.Type.Kind() == reflect.Ptr {
			fmt.Println(argType.Name, argType.Type.Elem().Kind())
		} else {
			if argType.Type.Kind() == reflect.Struct {
				fmt.Println("    =====>", argType.Name)
				run(argType.Type)
			} else {
				fmt.Println(argType.Name, argType.Type.Kind())
			}
		}
	}
}

type rtype struct {
	size       uintptr
	ptrdata    uintptr  // number of bytes in the type that can contain pointers
	hash       uint32   // hash of type; avoids computation in hash tables
	tflag      uint8    // extra type information flags
	align      uint8    // alignment of variable with this type
	fieldAlign uint8    // alignment of struct field with this type
	kind       uint8    // enumeration for C
	alg        *typeAlg // algorithm table
	gcdata     *byte    // garbage collection data
	str        int32    // string form
	ptrToThis  int32    // type for pointer to this type, may be zero
}
type typeAlg struct {
	// function for hashing objects of this type
	// (ptr to object, seed) -> hash
	hash func(unsafe.Pointer, uintptr) uintptr
	// function for comparing objects of this type
	// (ptr to object A, ptr to object B) -> ==?
	equal func(unsafe.Pointer, unsafe.Pointer) bool
}

type emptyInterface struct {
	typ  *rtype
	word unsafe.Pointer
}

func TypeOfTest(i interface{}) emptyInterface {
	eface := *(*emptyInterface)(unsafe.Pointer(&i))
	return eface
}
